'use strict'

const https = require('node:https')
const fmtMessage = require('./fmtSSEMessage.js')
const {httpcli} = require('gohttp')
const {Buffer} = require('node:buffer')

function checkAndSendMsg(ctx, data) {
  if (data.indexOf('event: ping') === 0) {
    ctx.write(fmtMessage({
      event: 'ping',
      data: {}
    }))

    return true
  }

  try {
    let dj = JSON.parse( data.substring(5).trim() )

    let msg = fmtMessage({
      event: dj.event || 'message',
      data: {
        conversation_id: dj.conversation_id,
        answer: dj.answer,
        task_id: dj.task_id,
        message_id: dj.message_id,
        id: dj.id
      }
    })

    dj.event === 'agent_message' && ctx.box.result.push(dj.answer)
    ctx.write(msg)
  } catch (err) {
    ctx.service.DEBUG && console.error('------error data begin\n', data, '-----end\n')
    ctx.service.DEBUG && console.error(err)
    return false
  }

  return true
}

async function agentChat(ctx, chat) {
  ctx.setHeader('content-type', 'text/event-stream;charset=utf-8').sendHeader()

  let protocol = chat.protocol || 'https:'

  let pr = new Promise((rv, rj) => {
    let req = https.request({
      port: chat.port || (protocol === 'https:' ? 443 : 80),
      protocol: protocol,
      host: chat.host,
      path: chat.api || chat.path,
      headers: {
        authorization: `Bearer ${chat.key}`,
        'content-type': 'application/json'
      },
      method: 'POST',
      rejectUnauthorized: false,
      requestCert: false,
      timeout: ctx.box.agentTimeout || 35_000,
      family: (chat.family && (chat.family === 4 || chat.family === 6))
              ? chat.family
              : 4
    })

    ctx.box.result = []

    req.on('response', res => {
        res.on('error', err => {
          rj(err)
        })

        let last_data = ''
        //sse的消息边界和data的边界可能不一致
        res.on('data', data => {
            let org_datas = data.toString()

            //data有可能是多个块，需要做数组切分
            if (last_data) {
              org_datas = `${last_data}${
                            (last_data.endsWith('}') || last_data.endsWith('}\n'))
                              ? '\n\n' : ''}${org_datas}`
              last_data = ''
            }

            let datalist = org_datas.split('\n\n').filter(p => p.length > 0)
            //let msglist = []
            if (datalist.length === 1) {
              if (!checkAndSendMsg(ctx, datalist[0])) {
                last_data = datalist[0]
              }
            } else {
              last_data = datalist.pop()
              for (let data of datalist) {
                checkAndSendMsg(ctx, data)              
              }
            }

        })
        //end data

        res.on('end', () => {
          last_data && checkAndSendMsg(ctx, last_data)
          last_data = ''
          rv()
        })
    })

    req.on('error', err => {
      req.destroy()
      rj(err)
    })

    req.write(JSON.stringify({
      response_mode: 'streaming',
      inputs: ctx.body.inputs || {},
      query: ctx.body.query,
      conversation_id: ctx.body.conversation_id || '',
      user: ctx.user ? ctx.user.id : 'eoms-default-user'
    }))

    req.end()
  })

  return pr
}

async function agentBlockingChat(ctx, chat) {
  let protocol = chat.protocol || 'https:'

  let pr = new Promise((rv, rj) => {
    let req = https.request({
      port: chat.port || (protocol === 'https:' ? 443 : 80),
      protocol: protocol,
      host: chat.host,
      path: chat.api || chat.path,
      headers: {
        authorization: `Bearer ${chat.key}`,
        'content-type': 'application/json'     
      },
      method: 'POST',
      rejectUnauthorized: false,
      requestCert: false,
      timeout: ctx.box.agentTimeout || 50000,
      family: (chat.family && (chat.family === 4 || chat.family === 6))
              ? chat.family
              : 4
    })

    req.on('response', res => {
        res.on('error', err => {
          rj(err)
        })

        let buffers = []
        let totalLength = 0

        res.on('data', data => {
          buffers.push(data)
          totalLength += data.length
        })

        res.on('end', () => {
          let data = Buffer.concat(buffers, totalLength)
          buffers = null
          rv(data)
        })
    })

    req.on('error', err => {
      req.destroy()
      rj(err)
    })

    req.write(JSON.stringify({
      response_mode: 'blocking',
      inputs: ctx.body.inputs || {},
      query: ctx.body.query,
      conversation_id: ctx.body.cid || ctx.body.conversation_id || '',
      user: ctx.user ? ctx.user.id : 'eoms-default-user'
    }))

    req.end()
  })

  return pr
}

/**
 * 
 * @param {object} chat 
 */
async function getConversations(ctx, chat) {
  let api = `${chat.protocol}//${chat.host}/v1/conversations`

  let query = {
    limit: 25,
    user: ctx.user ? ctx.user.id : 'eoms-default-user'
  }

  return httpcli.get(api, {
    headers: {
      authorization: `Bearer ${chat.key}`,
      'content-type': 'application/json'
    },
    query
  })
}

/**
 * @param {object} ctx
 * @param {object} chat 
 * @param {string} cid 
 */
async function deleteConversations(ctx, chat, cid) {
  let api = `${chat.protocol}//${chat.host}/v1/conversations/${cid}`

  return httpcli.delete(api, {
    headers: {
      authorization: `Bearer ${chat.key}`,
      'content-type': 'application/json'
    },
    body: {
      user: ctx.user ? ctx.user.id : 'eoms-default-user'
    }
  })
}

/**
 * 用于停止一个会话的当前对话任务
 * @param {object} ctx
 * @param {object} chat 
 * @param {string} task_id 
 */
async function stopTask(ctx, chat, task_id) {
  let api = `${chat.protocol}//${chat.host}/v1/chat-messages/${task_id}/stop`

  return httpcli.post(api, {
    headers: {
      authorization: `Bearer ${chat.key}`,
      'content-type': 'application/json'
    },
    body: {
      user: ctx.user ? ctx.user.id : 'eoms-default-user'
    }
  })
}

/**
 * 
 * @param {object} ctx 
 * @param {object} chat 
 * @param {string} cid 
 */
async function getHistoryMessages(ctx, chat) {
  let api = `${chat.protocol}//${chat.host}/v1/messages`
  let query = {
    limit: 20,
    conversation_id: ctx.query.conversation_id,
    user: ctx.user ? ctx.user.id : 'eoms-default-user'
  }

  ctx.query.first_id && (query.first_id = ctx.query.first_id)

  return httpcli.get(api, {
    headers: {
      authorization: `Bearer ${chat.key}`,
      'content-type': 'application/json'
    },
    query
  })
}

module.exports = {
  agentChat,
  agentBlockingChat,
  getConversations,
  deleteConversations,
  stopTask,
  getHistoryMessages,
  fmtMessage
}

